#include "herm/base/socket/socket_base.h"
#include "herm/base/socket/socket_os.h"
#include "address.h"

namespace herm{
Address::Address()
{
	Init();
}

Address::Address(const std::string& ip, uint16_t port)
{
	Set(ip, port);
}

Address::Address(uint32_t ip, uint16_t port)
{
	Set(ip, port);
}

Address::Address(uint16_t port)
{
	Set(port);  
}

void Address::Set(const std::string& ip, uint16_t port)
{
	memset(&m_addr, '\0', sizeof(sockaddr_in));
	// TCP sin_family is same than UDP's.
	m_addr.sin_family = AF_INET;
	m_addr.sin_port = htons(port);
	m_addr.sin_addr.s_addr = inet_addr(ip.c_str());
}

void Address::Set(uint32_t ip, uint16_t port)
{
	memset(&m_addr, '\0', sizeof(sockaddr_in));
	// TCP sin_family is same than UDP's.
	m_addr.sin_family = AF_INET;
	m_addr.sin_port = port;
	m_addr.sin_addr.s_addr = ip;
}

void Address::Set(uint16_t port)
{
	memset(&m_addr, '\0', sizeof(sockaddr_in));
	// TCP sin_family is same than UDP's.
	m_addr.sin_family = AF_INET;
	m_addr.sin_port = htons(port);
	m_addr.sin_addr.s_addr = INADDR_ANY;
}

Address::~Address(void)
{
}

bool Address::operator==(const Address& addr) const
{
	return NetIP() == addr.NetIP() && NetPort() == addr.NetPort();
}

bool Address::operator!() const
{
	return false;
}

Address::operator void *() const
{
	return (void*)this;
}

void Address::Init()
{
	memset(&m_addr, '\0', sizeof(sockaddr_in));
}

void Address::SetDomain(const std::string& host, int port)
{
    Init();

    hostent* h = gethostbyname(host.c_str());
	if (h == nullptr)
        throw HERM_SOCKET_EXCEPTION(ST_PARSE_DOMAIN_FAILED);
	
	in_addr sin_addr = *(struct in_addr*)h->h_addr;
	char* ip = inet_ntoa(sin_addr);
    Set(ip, port);
}

std::string Address::IP() const
{
	return inet_ntoa(m_addr.sin_addr);
}

uint32_t Address::NetIP() const
{
	return m_addr.sin_addr.s_addr;
}

uint16_t Address::Port() const
{
	return ntohs(m_addr.sin_port);
}

uint16_t Address::NetPort() const
{
	return m_addr.sin_port;
}

const sockaddr_in& Address::SockAddr() const
{
	return m_addr;
}

void Address::SockAddr(const sockaddr_in& sin)
{
	m_addr = sin;
}
}
